package main

import (
	"bytes"
	"compress/zlib"
	"encoding/binary"
	"io"
)

const (
// 消息头的flag
	// ptc
	PTC_TYPE_FLAG = 0
	// rpc
	RPC_TYPE_FLAG = 1
	RPC_TYPE_REPLY = 1
	RPC_TYPE_ISREQUEST_MASK = 2
	RPC_TYPE_REQUEST = 3
	// 压缩
	PTC_TYPE_COMPRESS = 4
	RPC_TYPE_NULL_REPLY = 8
	PTC_TYPE_KEEP_ALIVE = 16
 )

//  @Desc: RO的协议头信息
type ROProtoHead struct {
	// 协议内容长度
	MsgBodyLen uint32
	// 协议id
	ProtoId uint32
	// 标记类型,二进制不同位不同意义,上面的const
	ProtoFlag uint32
	// sessionid
	SessionId uint64
	// tagid rpc专用
	TagId uint32
	// 包头长度
	HeadLen int
}

//  @Desc: 解析协议头
//  @param buf 协议完全内容
//  @return *ROProtoHead 协议头
func RODecodeProtoHead(buf []byte) (*ROProtoHead, error) {
	ret := &ROProtoHead{}
	readBuf := bytes.NewReader(buf)
	if err := binary.Read(readBuf, binary.LittleEndian, &ret.MsgBodyLen); err != nil {
		return nil, err
	}
	if err := binary.Read(readBuf, binary.LittleEndian, &ret.ProtoId); err != nil {
		return nil, err
	}
	if err := binary.Read(readBuf, binary.LittleEndian, &ret.ProtoFlag); err != nil {
		return nil, err
	}
	if (ret.ProtoFlag & RPC_TYPE_FLAG) > 0 ||
		(ret.ProtoFlag & RPC_TYPE_ISREQUEST_MASK) >0 {
		if err := binary.Read(readBuf, binary.LittleEndian, &ret.TagId); err != nil {
			return nil, err
		}
	}
	ret.HeadLen = len(buf) - readBuf.Len()
	//zap.S().Info("协议:", len(buf), readBuf.Len(), ret.MsgBodyLen, ret.HeadLen)
	return ret, nil
}

//  @Desc: 打包消息头和消息体
//  @param head 消息头
//  @param msgBody 消息体
//  @return []byte 打包后的完全消息
func ROEncode(head *ROProtoHead, msgBody []byte) ([]byte, error) {
	writeBuf := bytes.NewBuffer(nil)
	if err := binary.Write(writeBuf, binary.LittleEndian, uint32(len(msgBody)+head.HeadLen-4)); err != nil {
		return nil, err
	}
	if err := binary.Write(writeBuf, binary.LittleEndian, head.ProtoId); err != nil {
		return nil, err
	}
	if err := binary.Write(writeBuf, binary.LittleEndian, head.ProtoFlag); err != nil {
		return nil, err
	}
	if (head.ProtoFlag & RPC_TYPE_FLAG) > 0 ||
		(head.ProtoFlag & RPC_TYPE_ISREQUEST_MASK) > 0{
		if err := binary.Write(writeBuf, binary.LittleEndian, head.TagId); err != nil {
			return nil, err
		}
	}
	if err := binary.Write(writeBuf, binary.LittleEndian, msgBody); err != nil {
		return nil, err
	}
	return writeBuf.Bytes(), nil
}

//  @Desc: zlib解压缩
//  @param head 消息头
//  @param msgBody 消息体
//  @return []byte
func zlibUncompressMsgBody(head *ROProtoHead, msgBody []byte) []byte {
	if (head.ProtoFlag & PTC_TYPE_COMPRESS) > 0 {
		b := bytes.NewReader(msgBody)
		var out bytes.Buffer
		r, _ := zlib.NewReader(b)
		io.Copy(&out, r)
		return out.Bytes()
	}
	return msgBody
}

//  @Desc: zlib压缩
//  @param head 消息头
//  @param msgBody 消息体
//  @return []byte 压缩之后的结果
func zlibCompressMsgBody(head *ROProtoHead, msgBody []byte) []byte {
	if (head.ProtoFlag & PTC_TYPE_COMPRESS) > 0 {
		var in bytes.Buffer
		w := zlib.NewWriter(&in)
		w.Write(msgBody)
		w.Close()
		return in.Bytes()
	}
	return msgBody
}
